package com.gitee.qdbp.jdbc.tags;

import java.io.IOException;
import java.util.Collection;
import com.gitee.qdbp.able.jdbc.ordering.Ordering;
import com.gitee.qdbp.able.jdbc.ordering.Orderings;
import com.gitee.qdbp.jdbc.api.SqlBoot;
import com.gitee.qdbp.jdbc.plugins.ColumnNameResolver;
import com.gitee.qdbp.jdbc.plugins.impl.ColumnNamingConverter;
import com.gitee.qdbp.jdbc.sql.SqlBuffer;
import com.gitee.qdbp.jdbc.sql.SqlBuilder;
import com.gitee.qdbp.staticize.common.NodeMetaData;
import com.gitee.qdbp.staticize.exception.TagException;
import com.gitee.qdbp.staticize.tags.base.BaseTag;
import com.gitee.qdbp.staticize.tags.base.NextStep;
import com.gitee.qdbp.staticize.utils.TagUtils;
import com.gitee.qdbp.tools.utils.StringTools;
import com.gitee.qdbp.tools.utils.VerifyTools;

/**
 * 如果内容不为空, 则输出ORDER BY ${orderByCondition}<br>
 * &lt;orderby value="orderByCondition" /&gt;
 *
 * @author zhaohuihua
 * @version 20210504
 * @since 3.4.0
 */
public class OrderByTag extends BaseTag {

    protected final SqlBoot sqlBoot;
    private Object value;

    public OrderByTag(SqlBoot sqlBoot) {
        this.sqlBoot = sqlBoot;
    }

    public Object getValue() {
        return value;
    }

    public void setValue(Object value) {
        this.value = value;
    }

    @Override
    public NextStep doHandle() throws TagException, IOException {
        if (VerifyTools.isBlank(value)) {
            return NextStep.SKIP_BODY;
        }
        SqlBuffer sql;
        if (value instanceof String) {
            ColumnNameResolver resolver = new ColumnNamingConverter(sqlBoot.plugins());
            sql = sqlBoot.sqlTools().buildOrderBySql(Orderings.of((String) value), resolver);
        } else if (value instanceof SqlBuffer) {
            sql = sqlBoot.newSqlBuilder().ad("ORDER BY").ad((SqlBuffer) value).out();
        } else if (value instanceof SqlBuilder) {
            sql = sqlBoot.newSqlBuilder().ad("ORDER BY").ad((SqlBuilder) value).out();
        } else if (value instanceof Orderings) {
            ColumnNameResolver resolver = new ColumnNamingConverter(sqlBoot.plugins());
            sql = sqlBoot.sqlTools().buildOrderBySql((Orderings) value, resolver);
        } else if (value instanceof Collection) {
            Collection<?> list = (Collection<?>) value;
            Orderings orderings = new Orderings();
            for (Object item : list) {
                if (item instanceof Ordering) {
                    orderings.add((Ordering) item);
                } else {
                    throw new TagException("Attribute 'value' can only be passed in as "
                            + "'String' or 'Orderings' or 'SqlBuffer' object.");
                }
            }
            ColumnNameResolver resolver = new ColumnNamingConverter(sqlBoot.plugins());
            sql = sqlBoot.sqlTools().buildOrderBySql(orderings, resolver);
        } else {
            throw new TagException("Attribute 'value' can only be passed in as "
                    + "'String' or 'Orderings' or 'SqlBuffer' object.");
        }
        if (sql != null && !sql.isBlank()) {
            sql.prepend("ORDER BY", ' ');
            this.print(sql.getExecutableSqlString());
        }
        return NextStep.SKIP_BODY;
    }

    @Override
    public void doValidate(NodeMetaData metadata) throws TagException {
        if (value != null) {
            if (!(value instanceof String) && !(value instanceof SqlBuffer) && !(value instanceof SqlBuilder)
                    && !(value instanceof Orderings) && !(value instanceof Collection)) {
                throw new TagException("Attribute 'value' can only be passed in as "
                        + "'String' or 'Orderings' or 'SqlBuffer' object.");
            }
            if (value instanceof Collection) {
                Collection<?> list = (Collection<?>) value;
                for (Object item : list) {
                    if (!(item instanceof Ordering)) {
                        throw new TagException("Attribute 'value' can only be passed in as "
                                + "'String' or 'Orderings' or 'SqlBuffer' object.");
                    }
                }
            }
        }
        for (NodeMetaData item : metadata.getChildren()) {
            if (!TagUtils.isTextTag(item.getTagClass())) {
                throw new TagException("Content cannot exist in the tag body.");
            }
            String text = item.getAttributeValue("value", String.class);
            if (text != null && !StringTools.isAsciiWhitespace(text)) {
                throw new TagException("Content cannot exist in the tag body.");
            }
        }
    }
}
